package com.netkit;

import com.lamfire.utils.ObjectFactory;
import com.netkit.exception.ActionException;
import com.netkit.logger.Logger;
import com.netkit.message.Message;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MessageDispatcher {
	private static final Logger LOGGER = Logger.getLogger(MessageDispatcher.class);
	private final Map<Integer, Action> actionCache = new HashMap<Integer, Action>();
	private ActionChain chain = new ActionChain();

	public void dispatch(Session session, Message message) {
		dispatch(session.getContext(), session, message);
	}

	public void dispatch(NetkitContext context, Session session, Message message) {
		int messageID = message.getMessageId();
		try {
			Action action = getAction(context, messageID);
			if (action == null) {
				return;
			}
			action.setSession(session);
			Iterator it = null;
			List list = context.getActionFilterList();
			if (list != null) {
				it = list.iterator();
			}
			executeAction(it, action, message);
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
	}

	private synchronized void setCachedAction(int messageId, Action action) {
		this.actionCache.put(Integer.valueOf(messageId), action);
	}

	private Action getCachedAction(int messageId) {
		return (Action) this.actionCache.get(Integer.valueOf(messageId));
	}

	private Action getAction(NetkitContext context, int messageId) throws InstantiationException, IllegalAccessException {
		Action action = getCachedAction(messageId);
		if (action != null) {
			return action;
		}
		Class clazz = context.lookupRegisteredAction(messageId);
		if (clazz == null) {
			return null;
		}
		ObjectFactory factory = new ObjectFactory(clazz);
		action = (Action) factory.newInstance();
		if (action != null) {
			setCachedAction(messageId, action);
		}
		return action;
	}

	private synchronized void executeAction(Iterator<ActionFilter> it, Action action, Message message) throws ActionException {
		this.chain.setIterator(it);
		this.chain.doChain(action, message);
	}
}